package com.enation.app.javashop.core.member.service.impl;


import com.enation.app.javashop.core.client.trade.CouponClient;
import com.enation.app.javashop.core.member.MemberErrorCode;
import com.enation.app.javashop.core.member.model.dos.MemberCoupon;
import com.enation.app.javashop.core.member.model.dto.MemberCouponQueryParam;
import com.enation.app.javashop.core.member.model.vo.MemberCouponNumVO;
import com.enation.app.javashop.core.member.service.MemberCouponManager;
import com.enation.app.javashop.core.promotion.coupon.model.CouponUseTypeEnum;
import com.enation.app.javashop.core.promotion.coupon.model.dos.CouponDO;
import com.enation.app.javashop.core.promotion.coupon.model.dos.CouponTypeEnum;
import com.enation.app.javashop.core.trade.cart.model.enums.CheckedWay;
import com.enation.app.javashop.framework.context.UserContext;
import com.enation.app.javashop.framework.database.DaoSupport;
import com.enation.app.javashop.framework.database.Page;
import com.enation.app.javashop.framework.exception.ServiceException;
import com.enation.app.javashop.framework.security.model.Buyer;
import com.enation.app.javashop.framework.security.model.Seller;
import com.enation.app.javashop.framework.util.DateUtil;
import com.enation.app.javashop.framework.util.DictUtils;
import com.enation.app.javashop.framework.util.SqlUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;

/**
 * 会员优惠券
 *
 * @author Snow create in 2018/5/24
 * @version v2.0
 * @since v7.0.0
 */
@Service
public class MemberCouponManagerImpl implements MemberCouponManager {

    @Autowired
    @Qualifier("memberDaoSupport")
    private DaoSupport daoSupport;

    @Autowired
    private CouponClient couponClient;

    @Override
    @Transactional(value = "memberTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void receiveBonus(MemberCoupon memberCoupon) {
        if(StringUtils.isNotEmpty(memberCoupon.getReceiveOrder())){
            // 订单一次只能分享获取一张优惠券
            String sql = "SELECT COUNT(*) FROM es_member_coupon WHERE receive_order =?  and member_id= ?; ";
            Integer couponCount = this.daoSupport.queryForInt(sql, memberCoupon.getReceiveOrder(),UserContext.getBuyer().getUid());
            if(couponCount>0){
                throw new ServiceException("600","订单分享优惠券已领取!");
            }
        }
        Integer couponId = memberCoupon.getCouponId();
        CouponDO couponDO = this.couponClient.getModel(couponId);

        if (memberCoupon.getMemberId() != null) {

            //添加会员优惠券表
            memberCoupon.setTitle(couponDO.getTitle());
            memberCoupon.setCreateTime(DateUtil.getDateline());
            // 会员优惠券使用开始时间和使用结束时间
            Long startTime=couponDO.getStartTime();
            Long endTime=couponDO.getEndTime();
            if (couponDO.getUseTimeType() != null) {
                CouponUseTypeEnum couponUseTypeEnum = CouponUseTypeEnum.valueOf(couponDO.getUseTimeType());
                switch (couponUseTypeEnum) {
                    case PERIOD:
                        Integer usePeriod = couponDO.getUsePeriod();
                        startTime = DateUtil.getDateline();
                        endTime = startTime + (usePeriod+1) * 24 * 60 * 60L-1L;
                        break;
                    case FIX:
                        startTime = couponDO.getUseStartTime();
                        endTime = couponDO.getUseEndTime();
                        break;
                }
            }
            //  以较大结束时间为准
            endTime=(endTime.compareTo( couponDO.getEndTime())==1L)?endTime:couponDO.getEndTime();
            memberCoupon.setStartTime(startTime);
            memberCoupon.setEndTime(endTime);
            memberCoupon.setCouponPrice(couponDO.getCouponPrice());
            memberCoupon.setCouponThresholdPrice(couponDO.getCouponThresholdPrice());
            memberCoupon.setSellerId(couponDO.getSellerId());
            memberCoupon.setUsedStatus(0);
            memberCoupon.setSellerName(couponDO.getSellerName());
            memberCoupon.setReceiveOrder(memberCoupon.getReceiveOrder());
            memberCoupon.setCouponType(couponDO.getCouponType());
            this.daoSupport.insert(memberCoupon);

            // 修改优惠券已被领取的数量
            this.couponClient.addReceivedNum(couponId);
        }
    }


    @Override
    public Page<MemberCoupon> list(MemberCouponQueryParam param) {

        //当前登录的会员
        Buyer buyer = UserContext.getBuyer();
        //当前服务器时间
        long nowTime = DateUtil.getDateline();
        //sql 参数
        List where = new ArrayList();
        //sql
        StringBuffer sql = new StringBuffer();
        sql.append("select * from es_member_coupon where member_id = ?");
        where.add(buyer.getUid());

        // 判断读取可用或者不可用优惠券 1:未使用 2：已使用，3已过期,4为不可用优惠券（已使用和已过期）
        if (param.getStatus() != null && param.getStatus().intValue() == 1) {

            // 可用优惠券读取条件 当前时间大于等于生效时间 并且 当前时间小于等于失效时间且使用状态是未使用
            sql.append(" and end_time>=?  and used_status = 0 ");
            where.add(nowTime);
            // 并且 大于等于优惠券使用金额条件
            if (param.getOrderPrice() != null) {
                sql.append(" and coupon_threshold_price <= ?");
                where.add(param.getOrderPrice());
            }
        } else if (param.getStatus() != null && param.getStatus().intValue() == 2) {

            //已使用优惠券
            sql.append(" and used_status = 1");

        } else if (param.getStatus() != null && param.getStatus().intValue() == 3) {

            // 已过期优惠券读取条件 当前时间小于生效时间 或者 当前时间大于失效时间
            sql.append(" and end_time <?  and used_status = 0  ");
            where.add(nowTime);
        } else if (param.getStatus() != null && param.getStatus().intValue() == 4) {

            // 查询已使用和已过期的优惠券
            sql.append(" and ((end_time <?  and used_status = 0 ) or used_status = 1)  ");
            where.add(nowTime);
        }

        if (param.getSellerIds() != null && param.getSellerIds().length != 0) {
            sql.append(" and seller_id in (" + SqlUtil.getInSql(param.getSellerIds(), where) + ") ");
        }

        sql.append(" order by coupon_price desc");
        Page<MemberCoupon> webPage = this.daoSupport.queryForPage(sql.toString(), param.getPageNo(), param.getPageSize(), MemberCoupon.class, where.toArray());

        List<MemberCoupon> list = webPage.getData();
        if (list != null) {
            for (MemberCoupon memberCoupon : list) {
                if (memberCoupon.getEndTime() < nowTime && memberCoupon.getUsedStatus().equals(0)) {
                    memberCoupon.setUsedStatus(2);
                }
            }
        }
        webPage.setData(list);

        return webPage;
    }


    @Override
    public MemberCoupon getModel(Integer memberId, Integer mcId) {

        StringBuffer sql = new StringBuffer();
        sql.append("select * from es_member_coupon where member_id=? and mc_id=? ");
        MemberCoupon memberCoupon = this.daoSupport.queryForObject(sql.toString(), MemberCoupon.class, memberId, mcId);
        return memberCoupon;
    }

    @Override
    @Transactional(value = "memberTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void usedCoupon(Integer mcId,String orderSn) {
        String sql = "update es_member_coupon set used_status = 1 ,order_sn=? ,used_time=? where mc_id = ?";
        this.daoSupport.execute(sql, orderSn,DateUtil.getDateline(),mcId);
    }


    @Override
    public void checkLimitNum(Integer couponId) {
        CouponDO couponDO = this.couponClient.getModel(couponId);
        Buyer buyer = UserContext.getBuyer();

        int limitNum = couponDO.getLimitNum();

        String sql = "select count(0) from es_member_coupon where member_id=? and coupon_id=?";
        int num = this.daoSupport.queryForInt(sql, buyer.getUid(), couponId);

        if (couponDO.getReceivedNum() >= couponDO.getCreateNum()) {
            throw new ServiceException(MemberErrorCode.E203.code(), "优惠券已被领完");
        }
        if (limitNum != 0 && num > limitNum) {
            throw new ServiceException(MemberErrorCode.E203.code(), "优惠券限领" + limitNum + "个");
        }

    }

    @Override
    public List<MemberCoupon> listByCheckout(Integer sellerId, Integer memberId) {
        //sql 参数
        List where = new ArrayList();
        //sql
        StringBuffer sql = new StringBuffer("select  COUNT(coupon_id) coupon_num, coupon_id,coupon_threshold_price,coupon_price," +
                "title,start_time,end_time,used_status,seller_id,mc_id,seller_name " +
                " from es_member_coupon where member_id = ? and  used_status = 0 and start_time < ? and end_time > ? ");
        where.add(memberId);
        where.add(DateUtil.getDateline());
        where.add(DateUtil.getDateline());

        if(sellerId!=null){
            sql.append(" and seller_id= ? ");
            where.add(sellerId);
            sql.append(" GROUP BY coupon_id ");
        }

        sql.append(" order by coupon_price desc");
        //查询的所有优惠券
        List<MemberCoupon> couponList = this.daoSupport.queryForList(sql.toString(), MemberCoupon.class, where.toArray());

        if(couponList.size()==1 && couponList.get(0).getCouponId()==null){
             return new ArrayList<>();
        }
        return couponList;
    }


    @Override
    public MemberCouponNumVO statusNum() {

        //当前登录的会员
        Buyer buyer = UserContext.getBuyer();
        //当前服务器时间
        long nowTime = DateUtil.getDateline();

        //未使用的数量
        String unUsedSql = "select count(0) from es_member_coupon where member_id = ? " +
                "and start_time <= ? and end_time >= ? ";
        int unUsedNum = this.daoSupport.queryForInt(unUsedSql, buyer.getUid(), nowTime, nowTime);

        //已使用的数量
        String usedSql = "select count(0) from es_member_coupon where member_id = ? " +
                " and used_status = 1";
        int usedNum = this.daoSupport.queryForInt(usedSql, buyer.getUid());

        //已过期
        String expiredSql = "select count(0) from es_member_coupon where member_id = ? " +
                "  and end_time <?  ";
        int expiredNum = this.daoSupport.queryForInt(expiredSql, buyer.getUid(), nowTime);

        MemberCouponNumVO couponNumVO = new MemberCouponNumVO();
        couponNumVO.setExpiredNum(expiredNum);
        couponNumVO.setUseNum(usedNum);
        couponNumVO.setUnUseNum(unUsedNum);

        return couponNumVO;
    }

    @Override
    public CouponDO getOrderShareCoupon(String orderSn,Integer sellerId) {
        // 订单一次只能分享获取一张优惠券
        Integer memberId = UserContext.getBuyer().getUid();
        String sql = "SELECT COUNT(*) FROM es_member_coupon WHERE receive_order =? and member_id=? ; ";
        Integer couponCount = this.daoSupport.queryForInt(sql, orderSn,memberId);
        if(couponCount>0){
            return null;
        }
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);

        // 一个用户一天最多领取3张
        sql = "SELECT COUNT(*) FROM es_member_coupon WHERE create_time>? and create_time<?  and member_id=? ; ";
        couponCount = this.daoSupport.queryForInt(sql, startTime.toEpochSecond(ZoneOffset.UTC),endTime.toEpochSecond(ZoneOffset.UTC),memberId);
        // 读取字典配置
        String dictValue = DictUtils.getDictValue(null, "RED_COUPON_SELLER_"+sellerId, "RED_COUPON_SELLER");
        int maxCount = StringUtils.isEmpty(dictValue) ? 3 : Integer.valueOf(dictValue);
        if(couponCount>maxCount-1){
            return null;
        }
        // 订单分享可领取的优惠券
        long nowTime = DateUtil.getDateline();
        String sqlQuery = "SELECT * FROM es_coupon WHERE coupon_type = ?  and start_time < ? and end_time> ? and seller_id=? ; ";
        CouponDO couponDO = this.daoSupport.queryForObject(sqlQuery, CouponDO.class, CouponTypeEnum.RED_COUPON.value(), nowTime, nowTime, sellerId);
        return couponDO;
    }

    /**
     * 退还用户优惠券
     *
     * @param orderSn
     */
    @Override
    @Transactional(value = "memberTransactionManager",propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
    public void retrieveCoupon(String orderSn) {
        // 根据订单查询优惠券
        String sql = "SELECT * FROM es_member_coupon WHERE order_sn=? ; ";
        List<MemberCoupon> memberCouponList =this.daoSupport.queryForList(sql,MemberCoupon.class,orderSn);
        // 优惠券退回
        if (CollectionUtils.isEmpty(memberCouponList)) {
            return;
        }
        for (MemberCoupon memberCoupon : memberCouponList) {
            this.daoSupport.execute("UPDATE es_member_coupon SET used_status=0,order_sn= null,used_time=null WHERE mc_id=?",memberCoupon.getMcId());
        }
    }

    /**
     * 根据会员id 和优惠卷id 查询会员优惠券
     */
    @Override
    public MemberCoupon getNewCoupon(Integer memberId,Integer sellerId,String[] couponType) {
        long newTime = DateUtil.getDateline();
        List<Object> term = new ArrayList<>();
        term.add(memberId);
        term.add(sellerId);
        term.add(newTime);
        term.add(newTime);
        String str = SqlUtil.getInSql(couponType, term);
        String sql = "SELECT * FROM es_member_coupon mc LEFT JOIN es_coupon c on mc.coupon_id = c.coupon_id " +
                " WHERE mc.member_id = ? AND mc.seller_id = ?  AND mc.start_time <= ? AND mc.end_time >= ? " +
                " AND c.coupon_type in ("+str+") ORDER BY mc.create_time DESC ";
        return daoSupport.queryForObject(sql,MemberCoupon.class,term.toArray());
    }

    /**
     * 根据会员id 和优惠卷id 查询会员首单卷
     */
    @Override
    public Integer getCouponNum(Integer memberId,Integer sellerId,String userType) {
        String sql = "SELECT count(1) AS num FROM es_member_coupon mc LEFT JOIN es_coupon c on mc.coupon_id = c.coupon_id WHERE mc.member_id = ? AND mc.seller_id = ? AND c.coupon_type = ? ORDER BY mc.create_time DESC ";
        return daoSupport.queryForInt(sql,memberId,sellerId ,userType);
    }

    /**
     * 查询会员领券的情况
     */
    @Override
    public List<MemberCoupon> getMemberCoupon(Integer memberId, Integer[] couperId) {
        List<Object> term = new ArrayList<>();
        term.add(memberId);
        String str = SqlUtil.getInSql(couperId, term);
        String sql = "SELECT * from es_member_coupon where member_id = ? and coupon_id in ("+str+")";
        return daoSupport.queryForList(sql,MemberCoupon.class,term.toArray());
    }

    @Override
    public void retroBackCoupon(String orderSn) {
        String sql="SELECT * FROM es_member_coupon WHERE order_sn=? and used_status=1 limit 1";
        MemberCoupon memberCoupon = daoSupport.queryForObject(sql, MemberCoupon.class, orderSn);
        if(memberCoupon!=null){
             this.daoSupport.execute("UPDATE es_member_coupon SET used_status=0 WHERE order_sn=? and used_status=1",orderSn);
        }

    }

}
